SpringDataJpa的使用 | 您所在的位置:网站首页 › {articleimage} › SpringDataJpa的使用 |
本文已参与「新人创作礼」活动,一起开启掘金创作之路。 SpringDataJpa的使用 -- 条件查询、排序查询、分页查询本文以 Article.java 为数据存放类,操作接口为 ArticleRepository.java @Data lombok 的注解,用来生成 Getter、Setter、toString、hashCode 方法,当添加该注解的同时在添加 相应方法(如 toString())时,添加的方法不会被覆盖。 @NoArgsConstructor lombok 的注解,用来生成 无参构造函数。 @AllArgsConstructor lombok 的注解,用来生成 全参构造函数。 @JsonIgnore 用来破坏实体类序列化时,产生的无限递归循环。 在本次的测试中,还需要 重写 Author.java 的 toString 方法,目的是这两个类中必须有一方的 toString 方法没有外键属性,可以双方都没有。 Author.java /** * 作者 类 * * @author LJM */ @Data @Entity @NoArgsConstructor @AllArgsConstructor @Table(name = "AUTHOR") public class Author { /** * 作者 id */ @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "author_id", nullable = false) private Long authorId; /** * 作者 姓名 */ @Column(name = "author_Name", nullable = false) private String authorName; /** * 作者 简介 */ @Column(name = "author_referral", nullable = false) private String authorReferral; /** * 一对多 * 一方 * (被)维护方 * * 文章列表 */ @JsonIgnore @OneToMany(mappedBy = "author", fetch = FetchType.EAGER, cascade = {CascadeType.MERGE, CascadeType.REMOVE}) private List articleList; @Override public String toString() { return "Author{" + "authorId=" + authorId + ", authorName='" + authorName + '\'' + ", authorReferral='" + authorReferral + '\'' + '}'; } }Article.java /** * 文章 类 * * @author LJM */ @Data @Entity @NoArgsConstructor @AllArgsConstructor @Table(name = "ARTICLE") public class Article { /** * 文章 id */ @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "article_id", nullable = false) private Long articleId; /** * 文章 标题 */ @Column(name = "article_title", nullable = false) private String articleTitle; /** * 文章 内容 */ @Column(name = "article_content", nullable = false) private String articleContent; /** * 文章 类型 */ @Column(name = "article_type", nullable = false) private String articleType; /** * 文章 阅读量 */ @Column(name = "article_read_number", nullable = false) private Integer articleReadNumber; /** * 文章 点赞数 */ @Column(name = "article_likes_number", nullable = false) private Integer articleLikesNumber; /** * 多对一 * 多方 * 作者外键 * 维护方 */ @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "article_author_id", nullable = false) private Author author; }ArticleRepository.java 这只是最基础的内容,会后续添加 接口或方法 来增加功能。 public interface ArticleRepository extends JpaRepository { } 排序查询 法 一使用 JpaRepository 的 List findAll(Sort sort) 方法,无需添加新的 方法或接口。 Sort.by(String) 方法的参数是 字符串数组,可以添加一到多个类属性名来排序。 ascending 方法表示升序排序(默认就是),写法:Sort.by(String).ascending()。 descending 方法表示降序排序,写法:Sort.by(String).descending()。 根据多个类属性来排序时,是在不破坏前一个的排序结果的基础上对后一个进行排序,以此类推。 @Test public void test1(){ List articleList=articleRepository.findAll(Sort.by("articleType").ascending()); System.out.println("====== 升序(类型) ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); List articleList1=articleRepository.findAll(Sort.by("articleType","articleReadNumber").ascending()); System.out.println("====== 升序(类型)(阅读量) ======"); articleList1.stream().map(Objects::toString).forEach(System.out::println); } 如果 输入的类属性不存在就会报错,故需要:检验输入的类属性是否存在 @Test public void test2(){ List articleList=articleRepository.findAll(Sort.by("articleType1").ascending()); System.out.println("====== 升序(类型) ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); } org.springframework.data.mapping.PropertyReferenceException: No property 'articleType1' found for type 'Article'! Did you mean ''articleType''? 能不能设置按第一个属性升序,再按第二个属性降序呢?答案是:当然。by() 是静态方法,不支持变量调用,每一个 by() 后只能添加一个 排序方法。 但是,Sort 有一个 and(Sort) 方法,用来将两个 Sort 合并,该方法由变量调用,理论上可以无限叠加。 @Test public void test3(){ List articleList=articleRepository.findAll(Sort.by("articleType","articleReadNumber").ascending()); System.out.println("====== 升序(类型)(阅读量) ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); Sort sort=Sort.by("articleType").ascending(); sort=sort.and(Sort.by("articleReadNumber").descending()); List articleList1=articleRepository.findAll(sort); System.out.println("====== 类型升序、再阅读量降序 ======"); articleList1.stream().map(Objects::toString).forEach(System.out::println); } 分页查询 法 一使用 PagingAndSortingRepository 的 Page findAll(Pageable pageable) 方法,JpaRepository 继承了 PagingAndSortingRepository 接口,无需添加新的 方法或接口。 Page 几个常用的属性: content 数组 ,存放 List 的形式的数据。 pageable 类,与上面的方法的参数一致,存放了数据的总数、当前页数、当前排序属性 等等。用 PageRequest.of([页码],[页大小]) 创建 Pageable 变量,然后填入 Page findAll(Pageable) 方法即可。 @Test public void test4(){ Pageable pageable=PageRequest.of(0,5); Page articleList=articleRepository.findAll(pageable); System.out.println("====== 分页结果 0,5 ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); Pageable pageable1=PageRequest.of(0,30); Page articleList1=articleRepository.findAll(pageable1); System.out.println("====== 分页结果 0,30 ======"); articleList1.stream().map(Objects::toString).forEach(System.out::println); }注意:PageRequest.of(0, 5) 表示 第一页,每页5条;PageRequest.of(1, 5) 表示 第二页,每页5条。 当页数大于数据条数时,如果是第一页,不报错,查询全部;如果不是第一页,那么无法执行,即:当前页码的数据必须大于等于一条,才能成功执行。 我之前测试时,是报错的,现在又可以了。 @Test public void test5(){ Pageable pageable=PageRequest.of(1,5); Page articleList=articleRepository.findAll(pageable); System.out.println("====== 分页结果 0,5 ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); Pageable pageable2=PageRequest.of(1,10); Page articleList2=articleRepository.findAll(pageable2); System.out.println("====== 分页结果 0,30 ======"); articleList2.stream().map(Objects::toString).forEach(System.out::println); } 条件查询 法 一 使用 JpaRepository 提供的,通过使用关键字来实现的条件查询。功能丰富。Spring Data JPA 查询方法支持的关键字 如:根据文章类型查询、根据 文章 类型 和 部分文章内容 查询 等等。 /** * 文章 操作 接口 * * @author l'j'm */ public interface ArticleRepository extends JpaRepository { /** * 根据 文章 类型 查询 * * @param articleType 文章 类型 * * @return list */ List findByArticleType(String articleType); /** * 根据 文章 类型 查询 * * @param articleType 文章 类型 * * @return list */ List findAllByArticleType(String articleType); /** * 根据 文章 类型 和 部分文章内容 查询 * * @param articleType 文章 类型 * @param articleContent 文章内容 * * @return list */ List findByArticleTypeAndArticleContentLike(String articleType, String articleContent); }Jpa 支持的关键字中,已经描述的很详细了,不再重复描述。 标准的写法是以 findBy 开头的,当然 findAllBy 开头的结果是一样,但不建议。 @Test public void aVoid1(){ List articleList=articleRepository.findByArticleType("后端"); List articleList1=articleRepository.findAllByArticleType("后端"); System.out.println("====== 默认 ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 默认(All) ======"); articleList1.stream().map(Objects::toString).forEach(System.out::println); } @Test public void aVoid2(){ List articleList=articleRepository.findByArticleType("后端"); List articleList2=articleRepository .findByArticleType("后端",Sort.by("articleReadNumber").ascending()); List articleList3=articleRepository .findByArticleTypeAndArticleContentLike("后端","%好%"); System.out.println("====== 默认 ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 根据 文章 类型 查询,升序(阅读量) ======"); articleList2.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 根据 文章 类型 和 部分文章内容 查询 ======"); articleList3.stream().map(Objects::toString).forEach(System.out::println); } 组合 是指,三种不同的查询分类 两两结合 或 三个成组 地使用,可以适应比较复杂的查询。 条件 + 排序 法 一在 根据关键字实现的 接口方法中添加参数 Sort 就可以添加排序条件。 注意:方法名不能改,即 想要添加 排序,只需添加添加参数 Sort,不能改方法名。 为什么可以这样写呢? 因为,添加关键字来实现 条件查询,实现时是在内部解析 方法名,然后构建 SQL 语句,最后剩下 findAll(Sort) ,而该方法是有对应的解析方法的。 /** * 文章 操作 接口 * * @author l'j'm */ public interface ArticleRepository extends JpaRepository { /** * 根据 文章 类型 查询 * * @param articleType 文章 类型 * * @return list */ List findByArticleType(String articleType); /** * 根据 文章 类型 查询 并排序 * * @param articleType 文章 类型 * @param sort 排序条件 * * @return list */ List findByArticleType(String articleType, Sort sort); /** * 根据 文章 类型 和 部分文章内容 查询 * * @param articleType 文章 类型 * @param articleContent 文章内容 * * @return list */ List findByArticleTypeAndArticleContentLike(String articleType, String articleContent); /** * 根据 文章 类型 和 部分文章内容 查询 并排序 * * @param articleType 文章 类型 * @param articleContent 文章内容 * @param sort 排序条件 * * @return list */ List findByArticleTypeAndArticleContentLike(String articleType, String articleContent, Sort sort); } 测试 @Test public void aVoid2(){ List articleList=articleRepository.findByArticleType("后端"); List articleList2=articleRepository .findByArticleType("后端",Sort.by("articleReadNumber").ascending()); List articleList3=articleRepository .findByArticleTypeAndArticleContentLike("后端","%好%"); List articleList4=articleRepository .findByArticleTypeAndArticleContentLike("后端","%好%",Sort.by("articleReadNumber").ascending()); System.out.println("====== 默认 ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 根据 文章 类型 查询,升序(阅读量) ======"); articleList2.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 根据 文章 类型 和 部分文章内容 查询 ======"); articleList3.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 根据 文章 类型 和 部分文章内容 查询,升序(阅读量) ======"); articleList4.stream().map(Objects::toString).forEach(System.out::println); } 条件 + 分页 法 一在 根据关键字实现的 接口方法中添加参数 Pageable 就可以添加 分页条件。 注意:方法名不能改,即 想要添加 分页,只需添加添加参数 Pageable,不能改方法名。 为什么可以这样写呢? 因为,添加关键字来实现 条件查询时,实现是在内部解析 方法名,然后构建 SQL 语句,最后剩下 findAll(Pageable) ,而该方法是有对应的解析方法的。 /** * 文章 操作 接口 * * @author l'j'm */ public interface ArticleRepository extends JpaRepository { /** * 根据 文章 类型 查询 * * @param articleType 文章 类型 * * @return list */ List findByArticleType(String articleType); /** * 根据 文章 类型 查询 并 分页 * * @param articleType 文章 类型 * @param pageable 分页条件 * * @return list */ List findByArticleType(String articleType, Pageable pageable); /** * 根据 文章 类型 和 部分文章内容 查询 * * @param articleType 文章 类型 * @param articleContent 文章内容 * * @return list */ List findByArticleTypeAndArticleContentLike(String articleType, String articleContent); /** * 根据 文章 类型 和 部分文章内容 查询 并 分页 * * @param articleType 文章 类型 * @param articleContent 文章内容 * @param pageable 分页条件 * * @return list */ List findByArticleTypeAndArticleContentLike(String articleType, String articleContent, Pageable pageable); } 测试 @Test public void aVoid3(){ List articleList=articleRepository.findByArticleType("后端"); List articleList2=articleRepository .findByArticleType("后端",PageRequest.of(0,2)); List articleList3=articleRepository .findByArticleTypeAndArticleContentLike("后端","%好%"); List articleList4=articleRepository .findByArticleTypeAndArticleContentLike("后端","%好%",PageRequest.of(1,1)); System.out.println("====== 默认 ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 根据 文章 类型 查询,分页(0,2) ======"); articleList2.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 根据 文章 类型 和 部分文章内容 查询 ======"); articleList3.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 根据 文章 类型 和 部分文章内容 查询,分页(1,1) ======"); articleList4.stream().map(Objects::toString).forEach(System.out::println); } 分页 + 排序 法 一Pageable 类中有参数 Sort,只需 将配置好的 Sort 传入 Pageable 中即可 其他的 使用方法,与前文无异。 @Test public void void1(){ Sort sort=Sort.by("articleType").ascending(); List articleList=articleRepository.findAll(sort); System.out.println("====== 升序(类型) ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); Pageable pageable=PageRequest.of(1,5); Page articleList1=articleRepository.findAll(pageable); System.out.println("====== 分页结果 0,5 ======"); articleList1.stream().map(Objects::toString).forEach(System.out::println); // Pageable pageable1 = PageRequest.of(1, 5).withSort(sort); Pageable pageable1=PageRequest.of(1,5,sort); Page articleList2=articleRepository.findAll(pageable1); System.out.println("====== 分页结果 0,5 ======"); articleList2.stream().map(Objects::toString).forEach(System.out::println); } 条件 + 分页 + 排序注意 踩坑:没有 findBy...And...(String..., Pageable, Sort) 这种写法的。 原因:没有 findAll(Pageable, Sort) 这个基方法。 findByArticleType(String, Pageable) 和 findByArticleType(String, Sort) 可以执行,是因为有 findAll(Pageable),findAll(Sort) 这两个基方法。 法 一看了前文你应该猜到了,没错,就是 用关键字实现条件查询,再添加 带有排序的分页参数实现。 写法 是:findBy...And...(String..., Pageable),直接套用 条件 + 分页 方法即可 /** * 文章 操作 接口 * * @author l'j'm */ public interface ArticleRepository extends JpaRepository { /** * 根据 文章 类型 查询 * * @param articleType 文章 类型 * * @return list */ List findByArticleType(String articleType); /** * 根据 文章 类型 查询 并 分页 * * @param articleType 文章 类型 * @param pageable 分页条件 * * @return list */ List findByArticleType(String articleType, Pageable pageable); /** * 根据 文章 类型 和 部分文章内容 查询 * * @param articleType 文章 类型 * @param articleContent 文章内容 * * @return list */ List findByArticleTypeAndArticleContentLike(String articleType, String articleContent); /** * 根据 文章 类型 和 部分文章内容 查询 并 分页 * * @param articleType 文章 类型 * @param articleContent 文章内容 * @param pageable 分页条件 * * @return list */ List findByArticleTypeAndArticleContentLike(String articleType, String articleContent, Pageable pageable); } 测试 @Test public void void2(){ Sort sort=Sort.by("articleReadNumber").descending(); Pageable pageable=PageRequest.of(0,5); // Pageable pageable1 = PageRequest.of(0, 5).withSort(sort); Pageable pageable1=PageRequest.of(0,5,sort); List articleList=articleRepository.findByArticleType("后端",pageable); System.out.println("====== 后端,分页结果 (0,5) ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); List articleList2=articleRepository.findByArticleType("后端",pageable1); System.out.println("====== 后端,分页结果 (0,5),排序 ======"); articleList2.stream().map(Objects::toString).forEach(System.out::println); }关于 分组查询 和 统计查询 下篇更新。 (二发)如果对你有帮助,点赞可好!! |
CopyRight 2018-2019 实验室设备网 版权所有 |